<template>
	<div class="containers" :class="screenHeight <= 720 ? 'minScreen' : ''">
		<!-- zoom section -->
		<div class="zoom-button-section">
			<el-button icon="el-icon-zoom-in" circle size="small" @click.prevent="onZoomIn"></el-button>
			<el-button icon="el-icon-zoom-out" circle size="small" @click.prevent="onZoomOut"></el-button>
			<el-button circle size="small" @click.prevent="onZoomReset">
				<img src="@/assets/img/zoom-reset.svg" alt="" style="width: 12px" />
			</el-button>
		</div>
		<div class="canvas" ref="canvas"></div>
		<!-- 模板容器 -->
		<div v-if="showTemplate" width="50%" class="ai-template-container">
			<AiTemplateView :showTemplate="showTemplate" :taskId="taskId" @onClose="onClose" @onOk="onSave" :workstep="workstep" />
		</div>
	</div>
</template>

<script>
import { mapActions, mapState } from 'vuex';
import PaletteProvider from 'bpmn-js/lib/features/palette/PaletteProvider';
import ContextPadProvider from 'bpmn-js/lib/features/context-pad/ContextPadProvider';
import BpmnModdle from 'bpmn-moddle';
import { getTitle, getAllWorkstepName, getAllParentNodes } from '../utility/utility';
import { isAssociatedVariableTemplete, isSameVariable } from '../utility/validate';
import AIWorkflow from '@/modules/workFlow.js';
import AiTemplateView from '@/views/AiWorkFlow/AiTemplateView/index.vue';

import xmlStr from '../mock/diagram.bpmn';
import CustomPalette from '../lib/bpmn/index';
import aiPackage from '../assets/aiWorkflow';
import Draggabilly from 'draggabilly';

export default {
	name: 'BpmnWorkflow',
	components: {
		AiTemplateView
	},
	props: {
		isShowPalette: {
			type: Boolean,
			default: false
		},
		uploadConfig: {
			type: Object,
			default: () => {}
		},
		bpmn: {
			type: String,
			default: null
		},
		showDetail: {
			type: Boolean,
			default: () => false,
			required: true
		},
		screenHeight: {
			type: Number,
			default: () => 1080,
			required: true
		},
		editBusinessId: {
			type: Number,
			default: () => 0,
			required: true
		}
	},
	data() {
		return {
			bpmnModeler: null,
			container: null,
			canvas: null,
			title: '',
			zoomScale: 1,
			draggee: null,
			showVariableDialog: false, //是否显示关联变量
			variableSelectIndex: ''
		};
	},
	computed: {
		...mapState('workflow', ['isShowConfirmInfo', 'worksteps', 'taskId', 'curShowNode', 'messageSummarySource', 'startNode']),
		...mapState({
			invalidVariableList: state => state.associatedVariable.invalidVariableList
		}),
		showTemplate() {
			return AIWorkflow.getTalkId(this.taskId) === this.curShowNode;
		},
		dialogVisible: {
			// getter
			get: function () {
				return (
					this.curShowNode === 'messageSure' ||
					this.curShowNode === 'hangup' ||
					this.curShowNode === 'sendMessage' ||
					this.curShowNode === 'speakWaiting' ||
					this.curShowNode === 'transfer' ||
					this.curShowNode === 'requestLocation' ||
					this.curShowNode === 'messageCollect' ||
					this.curShowNode === 'detectLivingFace' ||
					this.curShowNode === 'faceCompare' ||
					this.curShowNode === 'messageCollect' ||
					this.curShowNode === 'requestLocation' ||
					this.curShowNode === 'scanCode' ||
					this.curShowNode === 'signContract' ||
					this.curShowNode === 'ivvr' ||
					this.curShowNode === 'idCardCompare' ||
					this.curShowNode === 'sendForm' ||
					this.curShowNode === 'waitingRead' ||
					this.curShowNode === 'sceneTransfer' ||
					this.curShowNode === 'summaryConfirm' ||
					this.curShowNode === 'silentWating' ||
					this.curShowNode === 'optionJudge' ||
					this.curShowNode === 'messageSummary' ||
					this.curShowNode === 'sendContents' ||
					this.curShowNode === 'nlp' ||
					this.curShowNode === 'soundReception' ||
					this.curShowNode === 'variableJudge' ||
					this.curShowNode === 'sendDeposition' ||
					this.curShowNode === 'sendSign' ||
					this.curShowNode === 'variableCollection' ||
					this.curShowNode === 'inviteHumanThreeParties' ||
					this.curShowNode === 'collectShortVideo' ||
					this.curShowNode === 'interfaceCall' ||
					this.curShowNode === 'llm'
				);
			},
			// setter
			set: function () {}
		},
		workstep: {
			// getter
			get: function () {
				return this.worksteps[this.taskId] || {};
			},
			// setter
			set: function () {}
		},
		nextStepOption: {
			// getter
			get: function () {
				// const steps = getAllWorkstepName(Object.keys(this.worksteps),this.taskId)
				console.log(this.worksteps);
				const steps = getAllWorkstepName(this.worksteps);
				return steps;
			},
			// setter
			set: function () {}
		},
		// 推送表单，所有完整表单
		setFormIds: {
			get: function () {
				const forms = getAllWorkstepName(this.worksteps);
				const fromIds = forms.filter(item => item.taskId && item.taskId.startsWith('sendForm') && item.completed);
				return fromIds;
			},
			set: function () {}
		},

		// 所有使用的业务场景转接ID
		setScenIds: {
			get: function () {
				const scens = getAllWorkstepName(this.worksteps);
				const scenIds = scens.filter(item => item.taskId && item.taskId.startsWith('sceneTransfer') && item.completed);
				return scenIds;
			},
			set: function () {}
		},
		setSceneTransfer: {
			get: function () {
				const steps = getAllWorkstepName(this.worksteps);
				const sceneList = steps.filter(item => item.taskId && item.taskId.startsWith('sceneTransfer'));
				console.log('sceneList:', sceneList);
				return sceneList;
			},
			set: function () {}
		},
		// 证言抄录，所有使用的证言抄录的ID
		setTestimonyIds: {
			get: function () {
				const testimony = getAllWorkstepName(this.worksteps);
				const testimonyIds = testimony.filter(item => item.taskId && item.taskId.startsWith('sendDeposition') && item.completed);
				return testimonyIds;
			},
			set: function () {}
		}
	},
	watch: {
		taskId: function (newTaskId) {
			this.title = getTitle(newTaskId);
		},
		isShowPalette: function (newValue, preVelue) {
			if (preVelue !== newValue) {
				this.showPalette();
			}
		},
		bpmn: function (newbpmn, oldbpmn) {
			if (!newbpmn || newbpmn !== oldbpmn) {
				if (!this.bpmnModeler) {
					this.init();
					this.dragPalette();
					AIWorkflow.setTalks(this.worksteps);
				}
			}
		},
		invalidVariableList: {
			handler() {
				// 更新关联模板完成状态
				const self = this;
				this.$nextTick(() => {
					self.verifyInvalidVariables();
				});
			},
			immediate: true,
			deep: true
		}
	},
	mounted() {
		// this.init();
		this.showPalette();
	},
	beforeDestroy() {
		// 清空数据
		this.resetWorkflowState();
		window.aiWorkFlowlId = 1;
		if (this.bpmnModeler) {
			// 必须调用destroy方法，否则垃圾数据会影响下次的渲染
			this.bpmnModeler.destroy();
			this.bpmnModeler = null;
		}
	},
	methods: {
		...mapActions('workflow', ['addWorkStep', 'resetCurShowNode', 'setUpdatedNextSteps', 'resetWorkflowState', 'setFormIds', 'setLocalEditWorkStep', 'verifyInvalidVariables']),

		closeVariable() {
			this.showVariableDialog = false;
		},
		sureVariable(key, data) {
			const { id, variableName, initializationMode, variableDescription, variableType, url, method, params, dataMasking } = data;
			this.form.associatedVariable.id = id;
			this.showVariableDialog = false;
			this.form.associatedVariable = {
				id,
				name: variableName,
				describe: variableDescription,
				initMode: initializationMode === '随路数据' ? 'user-data' : initializationMode === 'API获取' ? 'api-data' : 'non-init',
				type: variableType === '文字串' ? 'text' : variableType === '数字串' ? 'numericString' : 'numeric',
				url: url ? url : '',
				method: method ? method : '',
				params: params ? params : [],
				dataMasking: dataMasking ? dataMasking : {}
			};
			// this.form.associatedVariable = associatedVariable;
			// console.warn(associatedVariable, 'associatedVariable');
			console.log(key, data);
			console.log(this.form.associatedVariable, '关联变量', this.form);
		},

		showPalette() {
			const palette = document.getElementsByClassName('djs-palette');
			if (palette && palette.length > 0) {
				palette[0].style.display = this.isShowPalette ? 'block' : 'none';
				if (window.screen.height <= 720 && this.isShowPalette) {
					palette[0].style.transform = 'scale(0.7)';
					palette[0].style.left = '-20px';
					palette[0].style.top = '-60px';
				} else {
					palette[0].style.transform = 'scale(1.0)';
				}
			}
		},

		parseBpmn(bpmn) {
			return new Promise((resove, reject) => {
				let steps = [];
				let maxIndex = 0;
				const moddle = new BpmnModdle();
				moddle
					.fromXML(bpmn)
					.then(definitions => {
						const flowElements = definitions.rootElement.rootElements[0].flowElements;
						flowElements.map(element => {
							if (element.$type === 'bpmn:Task') {
								// $attrs: {ai:taskId: 'speakWaiting_1'}
								if (element.$attrs && element.$attrs['ai:taskId']) {
									const index = element.$attrs['ai:taskId'].split('_')[1];
									maxIndex = Math.max(maxIndex, parseInt(index, 10));
								}
								if (element.extensionElements) {
									if (element.extensionElements.values && element.extensionElements.values.length > 0 && element.extensionElements.values[0].$type === 'ai:steps') {
										const data = JSON.parse(element.extensionElements.values[0].data);
										if (data && data.id) {
											const index = data.id.split('_')[1];
											maxIndex = Math.max(maxIndex, parseInt(index, 10));
										}
										steps.push(data);
									}
								}
							}
						});
						return resove({ steps, maxIndex });
					})
					.catch(err => {
						return reject(err);
					});
			});
		},
		init() {
			let self = this;
			// eslint-disable-next-line no-underscore-dangle
			let _getPaletteEntries = PaletteProvider.prototype.getPaletteEntries;
			PaletteProvider.prototype.getPaletteEntries = function () {
				let entries = _getPaletteEntries.apply(this);
				delete entries['create.data-object'];
				delete entries['create.end-event'];
				delete entries['create.exclusive-gateway'];
				delete entries['create.group'];
				delete entries['create.intermediate-event'];
				delete entries['create.intermediate-event'];
				delete entries['create.participant-expanded'];
				delete entries['create.subprocess-expanded'];
				delete entries['hand-tool'];
				delete entries['lasso-tool'];
				delete entries['space-tool'];
				delete entries['tool-separator'];
				delete entries['create.start-event'];
				delete entries['global-connect-tool'];
				delete entries['create.task'];
				delete entries['create.data-store'];
				return entries;
			};
			// eslint-disable-next-line no-underscore-dangle
			const _getContextPadEntries = ContextPadProvider.prototype.getContextPadEntries;
			ContextPadProvider.prototype.getContextPadEntries = function (element) {
				const entries = _getContextPadEntries.apply(this, [element]);

				delete entries['append.end-event'];
				delete entries['append.intermediate-event'];
				delete entries['append.gateway'];
				delete entries['append.append-task'];
				delete entries['append.text-annotation'];
				delete entries['replace'];
				// 删除连接线
				delete entries['connect'];
				if (element.id === 'StartEvent_1' || element.type !== 'bpmn:Task') {
					// 开始节点不能有删除菜单
					delete entries['delete'];
				}
				if (self.showDetail) {
					delete entries['delete'];
				}
				return entries;
			};

			this.title = getTitle(this.taskId);

			this.parseBpmn(this.bpmn || xmlStr)
				.then(value => {
					window.aiWorkFlowlId = value.maxIndex + 1;
					// value.steps.map(data => {
					// 	this.addWorkStep(data);
					// });
				})
				.catch(err => {
					console.error('parse bpmn error : ', err);
				});

			const canvas = this.$refs.canvas;
			this.bpmnModeler = new CustomPalette({
				container: canvas,
				additionalModules: [
					{
						__init__: ['labelEditingProvider'],
						labelEditingProvider: ['value', null],
						dropOnFlowBehavior: ['value', null],
						removeElementBehavior: ['value', null],
						bendpointMove: [
							'type',
							function () {
								// eslint-disable-next-line no-invalid-this
								this.start = function () {
									return false;
								};
								return false;
							}
						]
					}
				],
				moddleExtensions: {
					ai: aiPackage
				}
			});
			this.createNewDiagram();
			// const self = this;
			this.bpmnModeler.get('eventBus').on('node-delete-button-click', 999999, function (event) {
				self.$confirm(`确定要删除"${event.title}"吗？`)
					.then(() => {
						// detete node
						const modeling = self.bpmnModeler.get('modeling');
						const elementRegistry = self.bpmnModeler.get('elementRegistry');
						modeling.removeElements([elementRegistry.get(event.elementId)]);
					})
					.catch(() => {});
			});
		},
		createNewDiagram() {
			this.bpmnModeler
				.importXML(this.bpmn || xmlStr)
				.then(() => {
					// 这里是成功之后的回调, 可以在这里做一系列事情
					this.success();
				})
				.catch(err => {
					console.error(err);
				});
		},
		success() {
			this.bpmnModeler.get('canvas').zoom('fit-viewport', true);
			this.zoomScale = this.bpmnModeler.get('canvas').zoom();
		},
		// 下载为bpmn格式,done是个函数，调用的时候传入的
		async saveDiagram() {
			// // 把传入的done再传给bpmn原型的saveXML函数调用
			this.bpmnModeler.saveXML({ format: true }, function (err, xml) {
				let file = new Blob([xml]);
				let a = document.createElement('a'),
					url = URL.createObjectURL(file);
				a.href = url;
				a.download = 'diagram.bpmn';
				document.body.appendChild(a);
				a.click();
				setTimeout(function () {
					document.body.removeChild(a);
					window.URL.revokeObjectURL(url);
				}, 0);
				// done(err, xml)
			});
		},
		onClose() {
			this.resetCurShowNode();
		},
		onSave(value) {
			// {data, chagedNextSteps}
			// first to close form
			this.resetCurShowNode();
			setTimeout(() => {
				this.save(value);
			}, 10);
		},
		onZoomIn() {
			this.zoomScale += 0.1;
			if (this.zoomScale >= 2) {
				this.zoomScale = 2;
			}
			this.bpmnModeler.get('canvas').zoom(this.zoomScale);
		},
		onZoomOut() {
			this.zoomScale -= 0.1;
			if (this.zoomScale <= 0.2) {
				this.zoomScale = 0.2;
			}
			this.bpmnModeler.get('canvas').zoom(this.zoomScale);
		},
		onZoomReset() {
			this.zoomScale = 1;
			this.bpmnModeler.get('canvas').zoom(this.zoomScale);
			this.bpmnModeler.get('canvas').zoom('fit-viewport', true);
			this.zoomScale = this.bpmnModeler.get('canvas').zoom();
		},
		// 业务模板拖动
		dragPalette() {
			if (this.draggee) {
				return;
			}
			const handle = document.createElement('div');
			handle.innerHTML = '<div style="font-size:14px;font-weight: 700;color: #333333;line-height: 35px;margin-left:10px">业务模板</div>';
			handle.style.width = '171px';
			handle.style.height = '35px';
			handle.style.cursor = 'pointer';
			handle.style.borderBottom = '1px solid #F7F8FB';
			handle.className = 'draggie-handle';
			let elem = document.querySelector('.djs-palette');
			elem.insertBefore(handle, elem.childNodes[0]);
			this.draggee = new Draggabilly(elem, {
				// options...
				containment: '.canvas',
				handle: '.draggie-handle'
			});
			this.draggee.on('dragEnd', function (event, pointer) {
				if (window.screen.height <= 720) {
					elem.style.transform = 'scale(0.7)';
				} else {
					elem.style.transform = 'scale(1.0)';
				}
				console.log(event, pointer);
			});
			this.showPalette();
		},
		// 过滤多余的节点
		filterWorkSteps(bpmnXml, worksteps) {
			return new Promise((resove, reject) => {
				let steps = {};
				const moddle = new BpmnModdle();
				moddle
					.fromXML(bpmnXml)
					.then(definitions => {
						const flowElements = definitions.rootElement.rootElements[0].flowElements;
						flowElements.map(element => {
							if (element.$type === 'bpmn:Task') {
								// console.log('element : ', element);
								// $attrs: {ai:taskId: "messageSure_1"}
								const taskId = element.$attrs ? element.$attrs['ai:taskId'] : '';
								if (worksteps && worksteps[taskId]) {
									steps[taskId] = worksteps[taskId];
								}
							}
						});
						if (worksteps.robotProperty) {
							steps.robotProperty = worksteps.robotProperty;
						}
						return resove(steps);
					})
					.catch(err => {
						return reject(err);
					});
			});
		},
		//前端确认内容展示信息确认节点
		getMessageSureOption(taskId) {
			const parentNotes = getAllParentNodes(this.worksteps, taskId);
			let nodes = Array.from(new Set(parentNotes));
			nodes = nodes.sort((a, b) => {
				return Number(a.split('_')[1]) > Number(b.split('_')[1]) ? 1 : -1;
			});
			console.log('getMessageSureOption : ', taskId, nodes);
			let sures = [];
			nodes.map(item => {
				if (item.includes('messageSure') && this.worksteps[item].completed) {
					const option = { node: item, name: getTitle(item) };
					sures.push(option);
				}
			});
			return sures;
		},

		// 信息汇总节点
		getMessageSummaryOption(taskId) {
			let sures = [];
			const parentNotes = getAllParentNodes(this.worksteps, taskId);
			let nodes = Array.from(new Set(parentNotes));
			if (nodes.includes(this.startNode)) {
				nodes = nodes.sort((a, b) => {
					return Number(a.split('_')[1]) > Number(b.split('_')[1]) ? 1 : -1;
				});
				console.log('getMessageSummaryOption : ', taskId, nodes);
				nodes.map(item => {
					console.log(item);
					if (
						item.includes('messageSure') ||
						item.includes('ivvr') ||
						item.includes('speakWaiting') ||
						item.includes('detectLivingFace') ||
						item.includes('faceCompare') ||
						item.includes('messageCollect') ||
						item.includes('silentWating') ||
						item.includes('requestLocation') ||
						item.includes('scanCode') ||
						item.includes('sendMessage') ||
						item.includes('signContract') ||
						item.includes('idCardCompare') ||
						item.includes('sendForm') ||
						item.includes('optionJudge') ||
						item.includes('sendContents') ||
						item.includes('nlp') ||
						item.includes('soundReception') ||
						item.includes('variableJudge') ||
						item.includes('sendDeposition') ||
						item.includes('sendSign') ||
						item.includes('variableCollection') ||
						item.includes('inviteHumanThreeParties') ||
						item.includes('collectShortVideo') ||
						item.includes('interfaceCall')
					) {
						//  && this.worksteps[item].completed && item !== this.startNode && getAllParentNodes(this.worksteps, item).length > 0
						const option = { node: item, name: getTitle(item) };
						sures.push(option);
					}
				});
			}

			return sures;
		},

		// 查阅信息来源选择的扫码模块
		waitingReadOption(taskId) {
			let waiting = [];
			let result = getAllParentNodes(this.worksteps, taskId);
			const steps = getAllWorkstepName(this.worksteps);
			/** 筛选包含扫码模块的父节点 */
			steps.forEach(item => {
				if (((item.taskId && item.taskId.startsWith('scanCode')) || item.taskId.startsWith('messageSummary')) && result.indexOf(item.taskId) > -1 && item.completed) {
					waiting.push(item);
				}
			});
			return waiting;
		},
		save(value) {
			console.log('保存流程', value);
			if (value) {
				if (value.data) {
					// 流程中被引用的变量作废，相关关联的模板标红
					if (value.data.completed && isAssociatedVariableTemplete(value.data)) {
						for (let variable of this.invalidVariableList) {
							if (isSameVariable(value.data, variable, false)) {
								value.data.completed = false;
								break;
							}
						}
					}
					this.addWorkStep(value.data);
				}
				if (value.chagedNextSteps) {
					this.setUpdatedNextSteps({ taskId: value.data.no, steps: value.chagedNextSteps });
				}
			}
		}
	}
};
</script>

<style scoped>
.containers {
	/* background-color: #ffffff; */
	width: 100%;
	height: calc(100vh - 52px);
}
.canvas {
	width: calc(100% - 30px);
	height: 100%;
	margin-left: 30px;
}
.panel {
	position: absolute;
	right: 0;
	top: 0;
	width: 300px;
}
.buttons {
	position: absolute;
	left: 20px;
	bottom: 20px;
}
.buttons li {
	display: inline-block;
	margin: 5px;
}
.buttons li a {
	color: #999;
	background: #eee;
	cursor: not-allowed;
	padding: 8px;
	border: 1px solid #ccc;
	text-decoration: none;
}
.buttons li a.active {
	color: #333;
	background: #fff;
	cursor: pointer;
}
.zoom-button-section {
	position: absolute;
	width: 32px;
	right: 20px;
	top: 110px;
	height: 120px;
	z-index: 1000;
}
/* .minScreen {
	zoom: 0.7 !important;
	transform: translateX(4.5%);
} */
</style>

<style lang="less">
@import '../css/templateTitle.less';
.zoom-button-section .el-button.is-circle {
	margin: 0 0 10px 0;
}
.zoom-button-section {
	.el-button + .el-button {
		margin-left: 0;
	}
}
</style>
